home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Environments / Small Eiffel 0.4.8 / lib_std / dictionary.e < prev    next >
Encoding:
Text File  |  1997-04-13  |  10.1 KB  |  516 lines  |  [TEXT/ttxt]

  1. -- Part of SmallEiffel -- Read DISCLAIMER file -- Copyright (C) 
  2. -- Dominique COLNET and Suzanne COLLIN -- colnet@loria.fr
  3. --
  4. class DICTIONARY[V,K]
  5. --
  6. -- Associative memory. Values of type `V' are stored using Keys of type `K'.
  7. --
  8.  
  9. inherit 
  10.    ANY 
  11.       redefine is_equal, copy 
  12.       end;
  13.  
  14. creation make, with_capacity
  15.  
  16. feature {DICTIONARY}
  17.    
  18.    keys: ARRAY[K];            
  19.      -- Index range [1 .. N].
  20.      -- Storage for keys. 
  21.     
  22.    store: ARRAY[V]; 
  23.      -- Index range [1 .. N].
  24.      -- Storage for items. An item and the corresponding key 
  25.      -- are stored at the same index. 
  26.     
  27.    buckets: FIXED_ARRAY[INTEGER];
  28.      -- Index range [0 .. modulus-1].
  29.      -- Entry is a hash code value. Return 0 when hash code not used or 
  30.      -- gives the start of the corresponding list in `chain'.
  31.    
  32.    chain: ARRAY[INTEGER]; 
  33.      -- Index range [1 .. N].
  34.      -- Chaining of `free' slot and used slot. Value 0 is an end of 
  35.      -- list.
  36.     
  37.    free: INTEGER;
  38.      -- First element of the free list in `chain' or 0 when no more
  39.      -- space.
  40.  
  41.    modulus: INTEGER;
  42.      -- To compute a hash value in range [0 .. modulus-1].
  43.    
  44.    Min_size: INTEGER is 16;
  45.      -- Minimum value for N of range [1.. N];
  46.     
  47.    has_mem: INTEGER;
  48.      -- Memory of the last look in `keys'/`store' or 0 when no
  49.      -- previous successfull looking.
  50.    
  51.    item_mem, item_mem_i, item_mem_j: INTEGER;
  52.      -- Memory of the last look using `item'.
  53.    
  54. feature {NONE}
  55.  
  56.    make is
  57.      -- Internal initial storage size of the dictionary is set to
  58.      -- the default `Min_size' value. Then, tuning of needed 
  59.      -- storage size is done automatically according to usage. 
  60.      -- If you are really sure that your dictionary is always 
  61.      -- really bigger than `Min_size', you may use `with_capacity'
  62.      -- to save some execution time.
  63.       do
  64.      modulus := 2 * Min_size;
  65.      !!buckets.make(modulus);
  66.      !!chain.make(1,Min_size);
  67.      !!store.make(1,Min_size);
  68.      !!keys.make(1,Min_size);
  69.      initialize;
  70.       end;
  71.    
  72.    with_capacity(medium_size: INTEGER) is
  73.      -- May be used to save some execution time if one is sure 
  74.      -- that storage size will rapidly become really bigger than
  75.      -- `Min_size'. When first `remove' occurs, storage size may 
  76.      -- naturally become smaller than `medium_size'. Afterall, 
  77.      -- tuning of storage size is done automatically according to
  78.      -- usage.
  79.       local
  80.      i: INTEGER;
  81.       do
  82.      from
  83.         i := Min_size;
  84.      until
  85.         i >= medium_size
  86.      loop
  87.         i := 2 * i;
  88.      end;
  89.      modulus := 2 * i;
  90.      !!buckets.make(modulus);
  91.      !!chain.make(1,i);
  92.      !!store.make(1,i);
  93.      !!keys.make(1,i);
  94.      initialize;
  95.       end;
  96.  
  97.    initialize is
  98.       local
  99.      i: INTEGER;
  100.       do
  101.      count := 0;
  102.      free := 1;
  103.      has_mem := 0;
  104.      item_mem := 0;
  105.      from
  106.         i := 1;
  107.      until
  108.         i = chain.count
  109.      loop
  110.         chain.put (i + 1, i);
  111.         i := i + 1;
  112.      end;
  113.      chain.put(0,i);
  114.      from
  115.         i := 0;
  116.      until
  117.         i >= modulus
  118.      loop
  119.         buckets.put (0,i);
  120.         i := i + 1;
  121.      end;
  122.       end;
  123.  
  124. feature 
  125.  
  126.    count: INTEGER;
  127.      -- Actual `count' of stored elements.
  128.  
  129.    empty: BOOLEAN is
  130.       do
  131.      Result := count = 0;
  132.       ensure
  133.      count = 0 implies Result
  134.       end;
  135.       
  136.    at, infix "@" (k: K): V is
  137.      -- Return the item stored at key `k'.
  138.       require
  139.      has(k)
  140.       local
  141.      foo: BOOLEAN;
  142.       do
  143.      foo := has(k);
  144.      Result := store.item(has_mem);
  145.       end;
  146.    
  147.    has(k: K): BOOLEAN is
  148.      -- Is there an item currently associated with key 'k' ?
  149.       do
  150.      if has_mem = 0 or else not k.is_equal(keys.item(has_mem)) then
  151.         from
  152.            has_mem := buckets.item(k.hash_code \\ modulus);
  153.         until
  154.            has_mem = 0 or else k.is_equal(keys.item(has_mem))
  155.         loop
  156.            has_mem := chain.item(has_mem);
  157.         end;
  158.      end;
  159.      Result := (has_mem /= 0);
  160.       end;
  161.    
  162.    key_at(x: V): K is
  163.      -- Retrieve the key used for `x'. 
  164.       local
  165.      i: INTEGER;
  166.       do
  167.      from  
  168.         i := 1;
  169.      until
  170.         i > count or else (x = item(i))
  171.      loop
  172.         i := i + 1;
  173.      end;
  174.      if i <= count then
  175.         Result := key(i);
  176.      end;
  177.       end;
  178.    
  179.    put(x: V; k: K) is
  180.      -- If there is as yet no key `k' in the dictionary, enter 
  181.      -- it with item `x'. Otherwise overwrite the item associated
  182.      -- with key `k'.
  183.       local
  184.      hash: INTEGER;
  185.       do
  186.      hash := k.hash_code \\ modulus;
  187.      if has_mem = 0 or else not k.is_equal(keys.item(has_mem)) then
  188.         from
  189.            has_mem := buckets.item (hash);
  190.         until
  191.            has_mem = 0 or else k.is_equal (keys.item (has_mem))
  192.         loop
  193.            has_mem := chain.item (has_mem);
  194.         end;
  195.         if has_mem = 0 then
  196.            if count >= store.count then
  197.           expand;
  198.            end;
  199.            keys.put(k, free);
  200.            store.put(x, free);
  201.            has_mem := free;
  202.            free :=chain.item(free);
  203.            chain.put(buckets.item(hash),has_mem);
  204.            buckets.put(has_mem,hash);
  205.            count := count + 1;
  206.            if count > modulus * 2 then
  207.           resize(2 * modulus);
  208.            end;
  209.         end;
  210.      else
  211.         store.put(x,has_mem);
  212.      end;
  213.      item_mem := 0;
  214.       end;
  215.  
  216.    remove(k: K) is
  217.      -- If there is an entry for key `k' remove it. 
  218.      -- Otherwise the call has no effect.
  219.       local
  220.      hash: INTEGER;
  221.      n, p: INTEGER;
  222.       do
  223.      hash := k.hash_code \\ modulus;
  224.      from
  225.         n := buckets.item(hash);
  226.      until
  227.         n = 0 or else k.is_equal (keys.item(n))
  228.      loop
  229.         p := n;
  230.         n := chain.item(n);
  231.      end;
  232.      if n /= 0 then
  233.         if p /= 0 then
  234.            chain.put(chain.item(n),p);
  235.         else
  236.            buckets.put(chain.item(n),hash);
  237.         end;
  238.         chain.put(free,n);
  239.         free := n;
  240.         count := count - 1;
  241.         if n = has_mem then
  242.            has_mem := 0;
  243.         end;
  244.         if count < store.count // 4 and then count > Min_size then
  245.            shrink;
  246.         end;
  247.      end;
  248.      item_mem := 0;
  249.       end;
  250.  
  251.    is_equal(other: like current): BOOLEAN is
  252.       local
  253.      i: INTEGER;
  254.      k: K;
  255.       do
  256.      if count = other.count then
  257.         from  
  258.            i := 1;
  259.            Result := true;
  260.         until
  261.            not Result or else i > count
  262.         loop
  263.            k := key(i);
  264.            if other.has(k) then
  265.           Result := equal_like(item(i),other.at(k));
  266.            else
  267.           Result := false;
  268.            end;
  269.            i := i + 1;
  270.         end;
  271.      end;
  272.       end;
  273.  
  274.    copy(other: like current) is
  275.       do
  276.      standard_copy(other);
  277.      keys := other.keys.twin;
  278.      store := other.store.twin;
  279.      buckets := other.buckets.twin;
  280.      chain := other.chain.twin;
  281.       end;
  282.  
  283. feature -- To provide iterating facilities :
  284.    
  285.    item(i: INTEGER): V is
  286.       require
  287.      1 <= i;
  288.      i <= count;
  289.       do
  290.      if item_mem = 0 then
  291.         first;
  292.         from  
  293.         until
  294.            i = item_mem
  295.         loop
  296.            forth;
  297.         end;
  298.         Result := store.item(item_mem_j);
  299.      elseif item_mem <= i then
  300.         from
  301.         until
  302.            i = item_mem
  303.         loop
  304.            forth;
  305.         end;
  306.         Result := store.item(item_mem_j);
  307.      else
  308.         item_mem := 0;
  309.         Result := item(i);
  310.      end;
  311.       ensure
  312.      item_mem = i;
  313.       end;
  314.    
  315.    key(i: INTEGER): K is
  316.       require
  317.      1 <= i;
  318.      i <= count;
  319.       local
  320.      v: V;
  321.       do
  322.      v := item(i);
  323.      Result := keys.item(item_mem_j);
  324.       end;
  325.    
  326. feature {NONE} 
  327.    
  328.    first is
  329.       require
  330.      count > 0;
  331.       local
  332.      i: INTEGER;
  333.       do
  334.      from
  335.         i := 0;
  336.      until
  337.         buckets.item(i) /= 0
  338.      loop
  339.         i := i + 1;
  340.      end;
  341.      item_mem_i := i;
  342.      item_mem_j := buckets.item(i);
  343.      item_mem := 1;
  344.       ensure
  345.      item_mem = 1;
  346.       end;
  347.  
  348.    forth is
  349.       require
  350.      item_mem < count;
  351.       local
  352.      i: INTEGER;
  353.       do
  354.      if chain.item(item_mem_j) /= 0 then
  355.         item_mem_j := chain.item(item_mem_j);
  356.      else
  357.         from
  358.            i := item_mem_i + 1;
  359.         until
  360.            buckets.item(i) /= 0
  361.         loop
  362.            i := i + 1;
  363.         end;
  364.         item_mem_i := i;
  365.         item_mem_j := buckets.item(i);
  366.      end;
  367.      item_mem := item_mem + 1;
  368.       ensure
  369.      item_mem = 1 + old item_mem;
  370.       end;
  371.  
  372. feature {NONE}
  373.  
  374.    tmp_buckets: FIXED_ARRAY[INTEGER] is
  375.       once
  376.          !!Result.with_capacity(512);
  377.       end;
  378.  
  379.    resize(new_mod: INTEGER) is
  380.       local
  381.      hash: INTEGER;
  382.      i, n, p: INTEGER;
  383.       do
  384.          tmp_buckets.copy(buckets);
  385.      buckets.make(new_mod);
  386.      from
  387.         i := 0;
  388.      until
  389.         i >= modulus
  390.      loop
  391.         from
  392.            n := tmp_buckets.item (i);
  393.         until
  394.            n = 0
  395.         loop
  396.            p := chain.item (n);
  397.            hash := keys.item(n).hash_code \\ new_mod ;
  398.            chain.put(buckets.item(hash),n);
  399.            buckets.put(n,hash) ;
  400.            n := p;
  401.         end;
  402.         i := i + 1;
  403.      end;
  404.      modulus := new_mod;
  405.      item_mem := 0;
  406.       end;
  407.  
  408.    expand is
  409.       local
  410.      i, old_size: INTEGER;
  411.       do
  412.      item_mem := 0;
  413.      old_size := store.count;
  414.      chain.resize (1, 2 * old_size);
  415.      keys.resize  (1, 2 * old_size);
  416.      store.resize (1, 2 * old_size);
  417.      from
  418.         i := old_size + 1;
  419.      until
  420.         i = chain.count
  421.      loop
  422.         chain.put (i + 1, i);
  423.         i := i + 1;
  424.      end;
  425.      chain.put (free, i);
  426.      free := old_size + 1;
  427.       end;
  428.  
  429.     shrink is
  430.       local
  431.      str  : ARRAY [V];
  432.      kys  : ARRAY [K];
  433.      chn  : ARRAY [INTEGER];
  434.      i, j : INTEGER;
  435.      k    : INTEGER;
  436.       do
  437.      !!kys.make (1, store.count // 2);
  438.      !!str.make (1, store.count // 2);
  439.      !!chn.make (1, store.count // 2);
  440.      from
  441.         i := 1;
  442.         j := 0;
  443.      until
  444.         j >= modulus
  445.      loop
  446.         from
  447.            k := buckets.item (j);
  448.            if k /= 0 then
  449.           buckets.put (i, j);
  450.            end;
  451.         until
  452.            k = 0
  453.         loop
  454.            kys.put (keys.item (k), i);
  455.            str.put (store.item (k), i);
  456.            k := chain.item (k) ;
  457.            
  458.            if k = 0 then
  459.           chn.put (0, i);
  460.            else
  461.           chn.put (i + 1, i);
  462.            end;
  463.            i := i + 1;
  464.         end;
  465.         j := j + 1;
  466.      end;
  467.      from
  468.         i := count + 1;
  469.      until
  470.         i >= chn.count
  471.      loop
  472.         chn.put (i + 1, i);
  473.         i := i + 1;
  474.      end;
  475.      chn.put (0, i);
  476.      free := count + 1;
  477.      -- *** MLK : chain.free;
  478.      chain := chn;
  479.      -- *** MLK : keys.free;
  480.      keys := kys;
  481.      -- *** MLK : store.free;
  482.      store := str;
  483.      item_mem := 0;
  484.       end;
  485.     
  486. feature {NONE}
  487.  
  488.    equal_like(v1, v2: V): BOOLEAN is
  489.      -- Note: to avoid calling `equal' :-(
  490.      -- Because SmallEiffel is not yet able to infer 
  491.      -- arguments types.
  492.       do
  493.      if v1.is_expanded_type then
  494.         Result := v1 = v2 or else v1.is_equal(v2);
  495.      elseif v1 = v2 then
  496.         Result := true;
  497.      elseif v1 = Void or else v2 = Void then
  498.      else
  499.         Result := v1.is_equal(v2);
  500.      end;
  501.       end;
  502.  
  503. invariant
  504.    
  505.    keys.lower = 1;
  506.    
  507.    keys.lower = store.lower and store.lower = chain.lower;
  508.    
  509.    keys.upper = store.upper and store.upper = chain.upper;
  510.    
  511.    buckets.lower = 0;
  512.    
  513.    buckets.upper = modulus - 1;
  514.    
  515. end -- DICTIONARY 
  516.